from scipy.optimize import minimize
import pandas as pd
import numpy as np
import downriskparity as dd
import empyrical
import matplotlib.pyplot as plt
from WindPy import w
if w.isconnected()!=1:
    w.start()

codelist = ['260101.OF','151001.OF','519068.OF','206009.OF','005911.OF'] # 可以切换代码来增加或者减少资产类别或者基金类别,读取excel，或者数据库
mystart = '2019-01-01'     #数据长度调整
myend   = '2020-06-05'

#全局参数
N = len(codelist)
yearLen = 52   # days=252,weeks=52,months=12
w0 = np.array([1./N]*N)  #初始权重
wsddata = w.wsd(codelist,'NAV_adj',mystart,myend,"Period=W") #day，Period为空，W,M
rawdata = pd.DataFrame(wsddata.Data,index=wsddata.Codes,columns=wsddata.Times).T
Rt = np.log(rawdata/rawdata.shift(1)).dropna()#对数收益率
print(Rt)

#功能函数
def downside_risk_cov(r):
    vd=np.matrix(empyrical.downside_risk(r))/np.sqrt(252)
    corr=r.corr()
    vd=np.dot(vd.T, vd)
    vd=np.multiply(vd, corr)
    return vd

def calculate_portfolio_var(w,r):
    v=downside_risk_cov(r)
    portrisk=np.dot(np.dot(w,v),w.T)
    return portrisk
#
def calculate_risk_contribution(w,r):
    v=downside_risk_cov(r)
    sigma = np.sqrt(calculate_portfolio_var(w, r))
    MRC = np.dot(v, w.T)
    RC = np.multiply(MRC, w.T) / sigma
    return RC

def downside_risk_equal(w,pars):
    ff=0
    r = pars[0]
    RC=calculate_risk_contribution(w,r)
    v=downside_risk_cov(Rt)
    for i in range(N):
        for j in range(N):
            ff = ff + np.square(RC[i] - RC[j]) / (np.sqrt((np.dot(w,np.dot(v,w.T)))))
    return ff

def downside_risk_equal_w(r):
    mycons = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bnds = tuple((0, 1) for x in range(N))
    R = r
    opts = minimize(downside_risk_equal, w0,args=[R],method='SLSQP', bounds=bnds, constraints=mycons)
    print(opts)
    return opts

#循环计算比例
data=[]
for i in range(yearLen,len(Rt)):
    currDay = Rt.index[i]
    # s = rt.cov() * yearLen
    rt = Rt[i - yearLen:i]
    opts = downside_risk_equal_w(rt)
    d=[currDay]+list(opts.x)
    data.append(d)
pos=pd.DataFrame(data,columns=['data']+codelist)
pos.to_excel(r'D:\pycharmcom\test20200630.xlsx')

#回测结果
# rpIndex = pd.DataFrame(index=Rt.index[Rt.index>=pos.index[0]],columns=['close','return']) # 指数起始时间根据首次调仓日期确定
# rpIndex['return'].fillna(0,inplace=True)
# wrp = w0 # initial weights of risk parity index
# for t in rpIndex.index:
#     # update weight array
#     if t in pos.index: # if t == re-balace day
#         wrp = pos[pos.index== t]['weight']
#     # cal the close price
#     rpIndex.loc[t,'return'] = np.dot(Rt.loc[t],wrp)
# rpIndex['close'] = 1000*np.exp(np.cumsum(rpIndex['return']))
#
# rpIndex.to_excel(r'D:\pycharmcom\test20200522-4.xlsx')
# rpIndex['close'].plot(figsize=(10,8),lw=2,title='Risk  Parity  Index') # figure(4)
# plt.show()

#绩效
# def my_port_ret_measure(rt):
#     # rt : log-return data series
#     nav = np.exp(np.cumsum(rt))
#     rAbs = nav[-1]-1
#     print('绝对收益率：%.4f'%(rAbs*100),'%')
#     rAnnual = rAbs/len(rt)*252
#     print('年化收益率：%.4f'%(rAnnual*100),'%')
#     hw = [1]
#     for t in range(len(nav)):
#         hw.extend([max(hw[-1],nav[t])])
#     mdd = np.min(nav/hw[1:]-1)
#     print('最大回撤：%.4f'%(mdd*100),'%')
#     sp = rt.mean()/ rt.std() * np.sqrt(252)
#     print('夏普比率：%.4f'%(sp))
#     return
# my_port_ret_measure(rpIndex['return'])


